<script setup lang="ts">
import type { FormValues } from './menu-data';

import type { MenuApi } from '#/api/types';

import { computed, ref } from 'vue';

import { useVbenDrawer } from '@vben/common-ui';
import { cloneDeep, getPopupContainer } from '@vben/utils';

import { useVbenForm } from '#/adapter/form';
import {
  createMenuApi,
  getAllMenuListApi,
  getMenuDetailApi,
  updateMenuApi,
} from '#/api/core/modules/menu';
import { $t } from '#/locales';

import { drawerSchema } from './menu-data';

// 定义菜单节点类型
interface MenuNode {
  id: number;
  menuName: string;
  children?: MenuNode[];
  isLeaf?: boolean;
  menuType?: string;
  parentId?: number;
  [key: string]: any;
}

const emit = defineEmits<{ reload: [] }>();

function addFullName(
  tree: MenuNode[],
  nameKey: string,
  separator: string,
): MenuNode[] {
  const traverse = (node: MenuNode, parents: string[] = []): void => {
    const currentName = node[nameKey];
    const allNames = [...parents, currentName];
    node.fullName = allNames.join(separator);

    if (node.children && node.children.length > 0) {
      node.children.forEach((child: MenuNode) => {
        traverse(child, allNames);
      });
    }
  };

  tree.forEach((node) => {
    traverse(node);
  });

  return tree;
}

// 自定义useBeforeCloseDiff简单实现
function useBeforeCloseDiff(options: {
  currentGetter: () => Promise<any>;
  initializedGetter: () => Promise<any>;
}) {
  const { initializedGetter, currentGetter } = options;
  const initialValues = ref<any>(null);

  const markInitialized = async (): Promise<void> => {
    initialValues.value = await initializedGetter();
  };

  const resetInitialized = (): void => {
    initialValues.value = null;
  };

  const onBeforeClose = async (): Promise<boolean> => {
    if (!initialValues.value) return true;
    const currentValues = await currentGetter();
    return (
      JSON.stringify(initialValues.value) === JSON.stringify(currentValues)
    );
  };

  return {
    markInitialized,
    onBeforeClose,
    resetInitialized,
  };
}

// 简化的formValueGetter
function defaultFormValueGetter(formApi: any) {
  return async (): Promise<any> => {
    return await formApi.getValues();
  };
}

interface DrawerProps {
  id?: number | string;
  update: boolean;
  parentId?: number;
}

const isUpdate = ref(false);
const title = computed(() => {
  return isUpdate.value ? $t('pages.common.edit') : $t('pages.common.add');
});

const [BasicForm, formApi] = useVbenForm({
  commonConfig: {
    componentProps: {
      class: 'w-full',
    },
    formItemClass: 'col-span-2',
    labelWidth: 90,
  },
  schema: drawerSchema(),
  showDefaultActions: false,
  wrapperClass: 'grid-cols-2',
});

async function setupMenuSelect(): Promise<void> {
  // 获取菜单列表（已是树形结构）
  const { data: menuTree } = await getAllMenuListApi();

  // 支持i18n
  const processI18n = (nodes: MenuNode[]): void => {
    nodes.forEach((node) => {
      node.menuName = $t(node.menuName);
      if (node.children && node.children.length > 0) {
        processI18n(node.children);
      }
    });
  };

  // 处理i18n
  processI18n(menuTree);

  // 限制菜单层级深度为2层（根节点 + 两层菜单）
  const limitTreeDepth = (tree: MenuNode[], maxDepth = 2): MenuNode[] => {
    // 创建新的树结构，只保留最大深度为maxDepth的节点
    const processNode = (node: MenuNode, currentDepth = 0): MenuNode => {
      const newNode = { ...node };

      // 如果当前深度小于最大深度且有子节点，则递归处理子节点
      if (
        currentDepth < maxDepth &&
        node.children &&
        node.children.length > 0
      ) {
        newNode.children = node.children
          .filter((child) => child.menuType !== 'F') // 过滤掉按钮类型
          .map((child) => processNode(child, currentDepth + 1));
      } else {
        // 超过深度或没有子节点，则清空子节点
        newNode.children = [];
        newNode.isLeaf = true;
      }

      return newNode;
    };

    // 处理树的每个根节点
    return tree.map((node) => processNode(node));
  };

  // 限制菜单树深度
  const limitedMenuTree = limitTreeDepth(menuTree);

  const fullMenuTree = [
    {
      id: 0,
      menuName: '根菜单',
      children: limitedMenuTree,
    },
  ];

  addFullName(fullMenuTree, 'menuName', ' / ');

  formApi.updateSchema([
    {
      componentProps: {
        fieldNames: {
          label: 'menuName',
          value: 'id',
        },
        getPopupContainer,
        listHeight: 300,
        showSearch: true,
        treeData: fullMenuTree,
        treeDefaultExpandAll: false,
        treeDefaultExpandedKeys: [0],
        treeLine: { showLeafIcon: false },
        treeNodeFilterProp: 'menuName',
        treeNodeLabelProp: 'fullName',
      },
      fieldName: 'parentId',
    },
  ]);
}

const { onBeforeClose, markInitialized, resetInitialized } = useBeforeCloseDiff(
  {
    initializedGetter: defaultFormValueGetter(formApi),
    currentGetter: defaultFormValueGetter(formApi),
  },
);

const [BasicDrawer, drawerApi] = useVbenDrawer({
  onBeforeClose,
  onClosed: handleClosed,
  onConfirm: handleConfirm,
  async onOpenChange(isOpen) {
    if (!isOpen) {
      return null;
    }
    drawerApi.setState({ loading: true });

    const { id, update, parentId } = drawerApi.getData() as DrawerProps;
    isUpdate.value = update;

    // 加载菜单树选择
    await setupMenuSelect();

    // 设置初始值
    await formApi.resetForm();

    // 如果是编辑模式，加载菜单详情
    if (id && update) {
      const { data } = await getMenuDetailApi(id);
      await formApi.setValues(data);
    }
    // 如果是添加子菜单，设置父级ID
    else if (parentId) {
      await formApi.setFieldValue('parentId', parentId);
    }

    await markInitialized();
    drawerApi.setState({ loading: false });
  },
});

async function handleConfirm(): Promise<void> {
  try {
    drawerApi.lock(true);
    const { valid } = await formApi.validate();
    if (!valid) {
      return;
    }
    const data = cloneDeep(await formApi.getValues()) as FormValues;

    // 转换数据类型
    data.sort = Number(data.sort);
    data.parentId = Number(data.parentId);

    await (isUpdate.value
      ? updateMenuApi(data.id, data as unknown as MenuApi.MenuTree)
      : createMenuApi(data as unknown as MenuApi.CreateMenuParam));

    resetInitialized();
    emit('reload');
    drawerApi.close();
  } catch (error) {
    console.error(error);
  } finally {
    drawerApi.lock(false);
  }
}

async function handleClosed(): Promise<void> {
  await formApi.resetForm();
  resetInitialized();
}

defineExpose({
  drawerApi,
});
</script>

<template>
  <BasicDrawer :title="title" class="w-[600px]">
    <BasicForm />
  </BasicDrawer>
</template>
